import java.util.Hashtable;
import java.util.Vector;

import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.ModificationItem;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;

/**
 * @(#)Main.java 2011-10-19 Copyright 2011 it.kedacom.local, Inc. All rights
 *               reserved.
 */

/**
 * (用一句话描述类的主要功能)
 * @author xiaojinghai
 * @date 2011-10-19
 */

public class Main {

	/**
	 * (用一句话描述方法的主要功能)
	 * @param args
	 */
	static DirContext dc = null;
	static String account = "Manager";// 操作LDAP的帐户。默认就是Manager。
	static String password = "itserver";// 帐户Manager的密码。
	static String root = "dc=kedacom,dc=local"; // LDAP的根节点的DC

	public static void main(String[] args) {
		init();
		// add();// 添加节点
		// delete("ou=hi,dc=kedacom,dc=local");//删除"ou=hi,dc=kedacom,dc=local"节点
		// modifyInformation("ou=hi,dc=kedacom,dc=local");//修改"ou=hi,dc=kedacom,dc=local"属性
		// renameEntry("ou=new,o=neworganization,dc=kedacom,dc=local","ou=neworganizationalUnit,o=neworganization,dc=kedacom,dc=local");//重命名节点"ou=new,o=neworganization,dc=kedacom,dc=local"
		// 遍历所有根节点
		// searchInformation("dc=kedacom,dc=local", "", "(objectclass=*)");
		// 遍历指定节点的分节点
		// searchInformation("o=it,dc=kedacom,dc=local", "", "(objectclass=*)");

		// System.out.println(getUserDN("xiaojinghai@kedacom.com"));

		close();
	}

	public static void init() {
		Hashtable<String, String> env = new Hashtable<String, String>();
		env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
		env.put(Context.PROVIDER_URL, "ldap://172.16.3.10:389/");
		env.put(Context.SECURITY_AUTHENTICATION, "simple");
		env.put(Context.SECURITY_PRINCIPAL, "cn=" + account + "," + root);
		env.put(Context.SECURITY_CREDENTIALS, password);
		try {
			dc = new InitialDirContext(env);// 初始化上下文
			System.out.println("认证成功");// 这里可以改成异常抛出。
		} catch (javax.naming.AuthenticationException e) {
			System.out.println("认证失败");
		} catch (Exception e) {
			System.out.println("认证出错：" + e);
		}
	}

	public static void add() {
		try {
			String newUserName = "hi";
			BasicAttributes attrs = new BasicAttributes();
			BasicAttribute objclassSet = new BasicAttribute("objectClass");
			objclassSet.add("top");
			objclassSet.add("organizationalUnit");
			attrs.put(objclassSet);
			attrs.put("ou", newUserName);
			dc.createSubcontext("ou=" + newUserName + "," + root, attrs);
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("Exception in add():" + e);
		}
	}

	public static void delete(String dn) {
		try {
			dc.destroySubcontext(dn);
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("Exception in delete():" + e);
		}
	}

	public static boolean renameEntry(String oldDN, String newDN) {
		try {
			dc.rename(oldDN, newDN);
			return true;
		} catch (NamingException ne) {
			System.err.println("Error: " + ne.getMessage());
			return false;
		}
	}

	/**
	 * 获取指定objectClass的定义
	 * @param name
	 */
	public static void getObjectClassDefinition(String name) {
		try {
			// Get the schema tree root
			DirContext schema = dc.getSchema("");

			// Get the schema object for "person"
			DirContext personSchema = (DirContext) schema.lookup("ClassDefinition/" + name);
			Attributes a = personSchema.getAttributes("");
			NamingEnumeration ane = a.getAll();

			while (ane.hasMore()) {
				Attribute attr = (Attribute) ane.next();
				String attrType = attr.getID();
				NamingEnumeration values = attr.getAll();

				while (values.hasMore()) {
					Object oneVal = values.nextElement();
					if (oneVal instanceof String) {
						System.out.println(attrType + ": " + (String) oneVal);
					} else {
						System.out.println(attrType + ": " + new String((byte[]) oneVal));
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 获取指定DN的objectClass定义
	 * @param DN
	 */
	public static void getDNObjectClassDefinition(String DN) {
		try {
			// Get context containing class definitions for the "cn=Ted Geisel"
			// entry
			DirContext tedClasses = dc.getSchemaClassDefinition(DN);

			// Enumerate the class definitions
			NamingEnumeration enum1 = tedClasses.search("", null);
			while (enum1.hasMore()) {
				Object o = enum1.next();
				System.out.println(((SearchResult) o).getName());

				Attributes a = ((SearchResult) o).getAttributes();
				NamingEnumeration ane = a.getAll();

				while (ane.hasMore()) {
					Attribute attr = (Attribute) ane.next();
					String attrType = attr.getID();
					NamingEnumeration values = attr.getAll();

					while (values.hasMore()) {
						Object oneVal = values.nextElement();
						if (oneVal instanceof String) {
							System.out.println(attrType + ": " + (String) oneVal);
						} else {
							System.out.println(attrType + ": " + new String((byte[]) oneVal));
						}
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 获取指定名字的Attribute定义
	 * @param name
	 */
	public static void getAttributeDefinition(String name) {
		try {
			// Get the schema tree root
			DirContext schema = dc.getSchema("");

			// Get the schema object for "person"
			DirContext personSchema = (DirContext) schema.lookup("AttributeDefinition/" + name);
			Attributes a = personSchema.getAttributes("");
			NamingEnumeration ane = a.getAll();

			while (ane.hasMore()) {
				Attribute attr = (Attribute) ane.next();
				String attrType = attr.getID();
				NamingEnumeration values = attr.getAll();

				while (values.hasMore()) {
					Object oneVal = values.nextElement();
					if (oneVal instanceof String) {
						System.out.println(attrType + ": " + (String) oneVal);
					} else {
						System.out.println(attrType + ": " + new String((byte[]) oneVal));
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 获取指定DN中指定名字的Attribute定义
	 * @param DN
	 * @param name
	 */
	public static void getDNAttributeDefinition(String DN, String name) {
		try {
			// Get an attribute of that type
			Attributes attrs = dc.getAttributes(DN, new String[] {
				name
			});
			Attribute cnAttr = attrs.get(name);

			// Get its attribute type definition
			DirContext cnSchema = cnAttr.getAttributeDefinition();
			// Get cnSchema's attributes
			Attributes cnAttrs = cnSchema.getAttributes("");

			NamingEnumeration ane = cnAttrs.getAll();
			while (ane.hasMore()) {
				Attribute attr = (Attribute) ane.next();
				String attrType = attr.getID();
				NamingEnumeration values = attr.getAll();

				while (values.hasMore()) {
					Object oneVal = values.nextElement();
					if (oneVal instanceof String) {
						System.out.println(attrType + ": " + (String) oneVal);
					} else {
						System.out.println(attrType + ": " + new String((byte[]) oneVal));
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static boolean modifyInformation(String dn) {
		try {
			ModificationItem[] mods = new ModificationItem[1];

			/* 添加属性 */
			// Attribute attr0 = new BasicAttribute("description",
			// "测试");
			// mods[0] = new ModificationItem(DirContext.ADD_ATTRIBUTE,attr0);

			/* 修改属性 */
			// Attribute attr0 = new BasicAttribute("description", "肖景海");
			// mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE,
			// attr0);

			/* 删除属性 */
			Attribute attr0 = new BasicAttribute("description", "肖景海");
			mods[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, attr0);
			dc.modifyAttributes(dn, mods);
			return true;
		} catch (NamingException ne) {
			ne.printStackTrace();
			System.err.println("Error: " + ne.getMessage());
			return false;
		}

	}

	/**
	 * @param base ：根节点(在这里是"dc=kedacom,dc=local")
	 * @param scope ：搜索范围,分为"base"(本节点),"one"(单层),""(遍历)
	 * @param filter ：指定子节点(格式为"(objectclass=*)",*是指全部，你也可以指定某一特定类型的树节点)
	 */
	public static void searchInformation(String base, String scope, String filter) {
		SearchControls sc = new SearchControls();
		if (scope.equals("base")) {
			sc.setSearchScope(SearchControls.OBJECT_SCOPE);
		} else if (scope.equals("one")) {
			sc.setSearchScope(SearchControls.ONELEVEL_SCOPE);
		} else {
			sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
		}

		NamingEnumeration ne = null;
		try {
			ne = dc.search(base, filter, sc);
			// Use the NamingEnumeration object to cycle through
			// the result set.
			while (ne.hasMore()) {
				System.out.println();
				SearchResult sr = (SearchResult) ne.next();
				String name = sr.getName();
				if (base != null && !base.equals("")) {
					System.out.println("entry: " + name + "," + base);
				} else {
					System.out.println("entry: " + name);
				}

				Attributes at = sr.getAttributes();
				NamingEnumeration ane = at.getAll();

				while (ane.hasMore()) {
					Attribute attr = (Attribute) ane.next();
					String attrType = attr.getID();
					NamingEnumeration values = attr.getAll();
					Vector vals = new Vector();
					// Another NamingEnumeration object, this time
					// to iterate through attribute values.
					while (values.hasMore()) {
						Object oneVal = values.nextElement();
						if (oneVal instanceof String) {
							System.out.println(attrType + ": " + (String) oneVal);
						} else {
							System.out.println(attrType + ": " + new String((byte[]) oneVal));
						}
					}
				}
			}
		} catch (Exception nex) {
			System.err.println("Error: " + nex.getMessage());
			nex.printStackTrace();
		}
	}

	public static void close() {
		if (dc != null) {
			try {
				dc.close();
			} catch (NamingException e) {
				System.out.println("NamingException in close():" + e);
			}
		}
	}

	public static String getUserDN(String email) {
		String userDN = "";

		try {
			SearchControls constraints = new SearchControls();
			constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
			NamingEnumeration en = dc.search(root, "mail=" + email, constraints);
			if (en == null) {
				System.out.println("Have no NamingEnumeration.");
			}
			if (!en.hasMoreElements()) {
				System.out.println("Have no element.");
			}
			while (en != null && en.hasMoreElements()) {// maybe more than one
														// element
				Object obj = en.nextElement();
				if (obj instanceof SearchResult) {
					SearchResult si = (SearchResult) obj;
					userDN += si.getName();
					userDN += "," + root;
				} else {
					System.out.println(obj);
				}
			}
		} catch (Exception e) {
			System.out.println("Exception in search():" + e);
		}

		return userDN;
	}
}
